import pygame
import math
from character import Character

class Ball(Character):
    # 构造函数
    def __init__(self, screen,):
        super().__init__(screen)

    # 碰到边缘反弹
    def bounce_edge(self):
        # 获取屏幕宽高
        screen_width = self.screen.get_width()
        screen_height = self.screen.get_height()

        # 碰到下上边缘反弹
        if (self.rect.bottom >= screen_height) or (self.rect.top <= 0):
            # 改变面向方向
            self.set_direction(-self.direction)
        # 碰到左右边缘反弹
        elif (self.rect.left <= 0) or (self.rect.right >= screen_width):
            # 改变面向方向
            self.set_direction(180 - self.direction)

    # 碰到球拍反弹
    def bounce_paddle(self, paddle):
        if self.rect.colliderect(paddle.rect):
            # 计算球与球拍的相对位置
            ball_center_x = self.rect.centerx
            ball_center_y = self.rect.centery
            paddle_center_x = paddle.rect.centerx
            paddle_center_y = paddle.rect.centery
            
            # 计算重叠量来判断主要碰撞方向
            dx = (self.rect.width + paddle.rect.width) / 2 - abs(ball_center_x - paddle_center_x)
            dy = (self.rect.height + paddle.rect.height) / 2 - abs(ball_center_y - paddle_center_y)
            
            # 根据最小重叠量确定碰撞边和法线向量
            if dx < dy:
                # 水平方向碰撞（左右边）
                if ball_center_x < paddle_center_x:
                    # 从左侧碰撞，法线向右
                    normal_x = 1
                    normal_y = 0
                else:
                    # 从右侧碰撞，法线向左
                    normal_x = -1
                    normal_y = 0
            else:
                # 垂直方向碰撞（上下边）
                if ball_center_y < paddle_center_y:
                    # 从上方碰撞，法线向上
                    normal_x = 0
                    normal_y = -1
                else:
                    # 从下方碰撞，法线向下
                    normal_x = 0
                    normal_y = 1
            
            # 将当前方向角度转换为入射向量
            incident_angle_rad = math.radians(self.direction)
            incident_x = math.cos(incident_angle_rad)
            incident_y = math.sin(incident_angle_rad)
            
            # 计算反射向量: R = I - 2(I·N)N
            dot_product = incident_x * normal_x + incident_y * normal_y
            reflect_x = incident_x - 2 * dot_product * normal_x
            reflect_y = incident_y - 2 * dot_product * normal_y
            
            # 将反射向量转换回角度
            reflection_angle = math.degrees(math.atan2(reflect_y, reflect_x))
            
            # 应用新的方向
            self.set_direction(reflection_angle)
            
            # 修正球的位置以防止卡入球拍
            if dx < dy:
                # 水平碰撞
                if ball_center_x < paddle_center_x:
                    # 左侧碰撞，将球放在球拍左侧
                    self.set_position(paddle.rect.left - self.rect.width, self.y)
                else:
                    # 右侧碰撞，将球放在球拍右侧
                    self.set_position(paddle.rect.right, self.y)
            else:
                # 垂直碰撞
                if ball_center_y < paddle_center_y:
                    # 上方碰撞，将球放在球拍上方
                    self.set_position(self.x, paddle.rect.top - self.rect.height)
                else:
                    # 下方碰撞，将球放在球拍下方
                    self.set_position(self.x, paddle.rect.bottom)

    # 碰到砖块反弹
    def bounce_brick(self, brick):
        if self.rect.colliderect(brick.rect):
            # 确定最小重叠方向
            ball_center_x = self.rect.centerx
            ball_center_y = self.rect.centery
            brick_center_x = brick.rect.centerx
            brick_center_y = brick.rect.centery
            
            # 计算重叠量
            dx = (self.rect.width + brick.rect.width) / 2 - abs(ball_center_x - brick_center_x)
            dy = (self.rect.height + brick.rect.height) / 2 - abs(ball_center_y - brick_center_y)
            
            # 基于入射角度和碰撞边计算反射
            if dx < dy:
                # 水平边碰撞，反转水平方向
                self.set_direction(180 - self.direction)
            else:
                # 垂直边碰撞，反转垂直方向
                self.set_direction(-self.direction)
            
            # 删除砖块
            brick.destroy()